package com.simple.common.entity.req.vm.pay;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.simple.common.framework.context.Contexts;
import lombok.Data;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import reactor.core.publisher.Flux;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * @author yasud
 * @date 2020年09月28日 17:02
 * @description
 */
@Data
public class DirectPayReqV2 extends DirectPayReqV1 {

    /**
     * 商品信息列表
     */
    @NotNull(message = "goods info not null")
    private List<Map<String, Object>> goodsInfo;

    /**
     * 物流信息
     */
    @NotNull(message = "shipping info not null")
    private Map<String, Object> shippingInfo;

    /**
     * 订单信息
     */
    @NotNull(message = "billing info no null")
    private Map<String, Object> billInfo;

    @SneakyThrows
    public String goodsListJson() {
        return Contexts.OBJECTMAPPER.writeValueAsString(getGoodsInfo());
    }

    @SneakyThrows
    public String shippingInfoJson() {
        return Contexts.OBJECTMAPPER.writeValueAsString(getShippingInfo());
    }

    @SneakyThrows
    public String billingInfoJson() {
        return Contexts.OBJECTMAPPER.writeValueAsString(getBillInfo());
    }

    @Override
    protected Map<String, Consumer<Object>> predicateMapping() {
        Map<String, Consumer<Object>> stringConsumerMap = super.predicateMapping();
        return stringConsumerMap;
    }

    @Override
    protected void checkOther() {
        Map<String, Consumer<Object>> goodsPredicateMapping = goodsPredicateMapping();
        Flux.fromStream(goodsInfo.stream()).index().subscribe(objects -> {
            Map<String, Object> t2 = objects.getT2();
            try {
                singleCheck(goodsPredicateMapping, t2, "goods info ");
            } catch (Exception ex) {
                String message = Throwables.getRootCause(ex).getMessage();
                Throwables.throwIfUnchecked(new RuntimeException("no. " + objects.getT1() + "  " + message));
            }
        });
        Map<String, Consumer<Object>> shippingPredicateMapping = shippingPredicateMapping();
        singleCheck(shippingPredicateMapping, shippingInfo, "shipping ");
        Map<String, Consumer<Object>> billingInfoPredicateMapping = billingInfoPredicateMapping();
        singleCheck(billingInfoPredicateMapping, billInfo, "billing ");
    }

    private void singleCheck(Map<String, Consumer<Object>> shippingPredicateMapping, Map<String, Object> shippingInfo, String propertyName) {
        try {
            shippingPredicateMapping.entrySet().forEach(v -> {
                String key = v.getKey();
                Consumer<Object> value = v.getValue();
                value.accept(shippingInfo.get(key));
            });
        } catch (Exception ex) {
            String message = Throwables.getRootCause(ex).getMessage();
            Throwables.throwIfUnchecked(new RuntimeException(propertyName + " property " + message));
        }
    }


    /**
     * 商品验证
     *
     * @return
     */
    private Map<String, Consumer<Object>> goodsPredicateMapping() {
        Map<String, Consumer<Object>> of = ImmutableMap.of(
                "sku", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "sku not blank");
                },
                "name", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "product name not blank");
                },
                "price", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "product price not blank");
                },
                "quantity", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "product Quantity not blank");
                }
        );
        return of;
    }

    /**
     * 物流信息验证
     *
     * @return
     */
    private Map<String, Consumer<Object>> shippingPredicateMapping() {
        Map<String, Consumer<Object>> of = Maps.newLinkedHashMap();
        of.put("shippingFreight", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "Freight not blank"));
        of.put("shippingFirstName", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "FirstName not blank"));
        of.put("shippingLastName", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "LastName not blank"));
        of.put("shippingAddress", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "Address1 not blank"));
        of.put("shippingCity", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "city not blank"));
        of.put("shippingCountry", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "country not blank"));
        of.put("shippingState", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "State not blank"));
        of.put("shippingZipcode", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "zipcode not blank"));
        of.put("shippingEmail", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "email not blank"));
        of.put("shippingTel", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "telephone not blank"));
        return of;
    }

    /**
     * 账单验证
     *
     * @return
     */
    private Map<String, Consumer<Object>> billingInfoPredicateMapping() {
        Map<String, Consumer<Object>> of = ImmutableMap.of(
                "billFirstName", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "first name not blank");
                },
                "billLastName", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "lastname not blank");
                },
                "billAddress", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "address 1 not blank");
                },
                "billCity", o -> {
                    Preconditions.checkState(StringUtils.isNotBlank((String) o), "city not blank");
                }
        );
        of = Maps.newLinkedHashMap(of);
        of.put("billCountry", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "country code not blank"));
        of.put("billState", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "state not blank"));
        of.put("billZipcode", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "zipcode not blank"));
        of.put("billEmail", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "email not blank"));
        of.put("billTel", o -> Preconditions.checkState(StringUtils.isNotBlank((String) o), "telephone not blank"));
        return of;
    }
}